package com.dlc.shop.delivery.common.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.dlc.shop.bean.enums.DeliveryCompanyType;
import com.dlc.shop.bean.model.OrderItem;
import com.dlc.shop.bean.model.UserAddrOrder;
import com.dlc.shop.common.bean.Quick100;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.util.Json;
import com.dlc.shop.config.ShopConfig;
import com.dlc.shop.delivery.common.bo.DeliveryPrintDataInfoBO;
import com.dlc.shop.delivery.common.bo.DeliveryPrintInfoBO;
import com.dlc.shop.delivery.common.bo.DeliveryPrintInfoErrorBO;
import com.dlc.shop.delivery.common.model.OutletConfig;
import com.dlc.shop.delivery.common.model.Printer;
import com.dlc.shop.delivery.common.param.DeliveryOrderItemParam;
import com.dlc.shop.delivery.common.service.OutletConfigService;
import com.dlc.shop.delivery.common.service.PrinterService;
import com.dlc.shop.service.UserAddrOrderService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/**
 * 电子面单接口
 * API接口调用无测试环境，但下单后不揽收不会计算快递费，快递公司对单号有一定的回收机制，
 * 客户接口调试只需在订单内备注、寄件人或收件人等写明“测试”或“无需取件”字段。
 * @author TRACK
 */
@Component
@AllArgsConstructor
public class DeliveryPrintManager {
    private static final Logger logger = LoggerFactory.getLogger(DeliveryPrintManager.class);
    private static final Integer MAX_CARGO_LENGTH = 20;
    private static final String METHOD = "order";
    private static final int MAP_INIT = 3;
    private static final int SUCCESS_CODE = 200;

    private final OutletConfigService outletConfigService;
    private final PrinterService printerService;
    private final UserAddrOrderService userAddrOrderService;
    private final ShopConfig shopConfig;

    public String deliveryPrint(DeliveryOrderItemParam deliveryOrderParam) {
        Quick100 quick100 = shopConfig.getQuick100();
        // 检查配置
        checkInfo(deliveryOrderParam, quick100);
        // 网点配置
        OutletConfig outletConfig = outletConfigService.getById(deliveryOrderParam.getOutletConfigId());
        // 打印机配置
        Printer printer = printerService.getById(deliveryOrderParam.getPrinterId());
        // 快递公司配置
        DeliveryCompanyType deliveryCompanyType = DeliveryCompanyType.instance(outletConfig.getDeliveryCompanyType());
        if (Objects.isNull(deliveryCompanyType)) {
            // 网点关联快递公司配置为空
            throw new YamiShopBindException("yami.outlet.delivery.is.null");
        }
        // 收件人信息
        Map<String, Object> recManMap = getManInfoMap(deliveryOrderParam.getReceiverName(), deliveryOrderParam.getReceiverMobile(), deliveryOrderParam.getAddrOrderId(),  "");;
        // 寄件人信息
        Map<String, Object> sendManMap = getManInfoMap(outletConfig.getShipper(), outletConfig.getMobile(), null, outletConfig.getPrintAddr());
        // 电子面单下单信息
        Map<String, Object> orderReqMap = getOrderReqMap(deliveryOrderParam, outletConfig, printer, deliveryCompanyType, recManMap, sendManMap, quick100);
        // 电子面单打印请求参数
        Map<String, Object> printReq = new HashMap<>(Constant.INITIAL_CAPACITY);
        printReq.put("method", METHOD);
        printReq.put("key", quick100.getKey());
        String param = JSON.toJSONString(orderReqMap);
        String t = String.valueOf(System.currentTimeMillis());
        String sign = new Digester(DigestAlgorithm.MD5).digestHex(param + t + quick100.getKey() + quick100.getSecret(), "UTF-8").toUpperCase(Locale.ROOT);
        printReq.put("sign", sign);
        printReq.put("t", t);
        printReq.put("param", param);
        String repJson = HttpUtil.post(quick100.getPrintReqUrl(), printReq);
        logger.info("电子面单请求返回：" + repJson);
        DeliveryPrintInfoBO deliveryPrintInfoBO = Json.parseObject(repJson, DeliveryPrintInfoBO.class);
        if (Objects.isNull(deliveryPrintInfoBO)) {
            DeliveryPrintInfoErrorBO deliveryPrintInfoErrorBO = Json.parseObject(repJson, DeliveryPrintInfoErrorBO.class);
            if (Objects.isNull(deliveryPrintInfoErrorBO)) {
                // 电子面单请求错误，请检查配置是否正确
                throw new YamiShopBindException("yami.delivery.print.error");
            }
            throw new YamiShopBindException(deliveryPrintInfoErrorBO.getMessage());
        }
        if (!deliveryPrintInfoBO.getSuccess() || !Objects.equals(deliveryPrintInfoBO.getCode(), SUCCESS_CODE)) {
            throw new YamiShopBindException(deliveryPrintInfoBO.getMessage());
        }
        DeliveryPrintDataInfoBO deliveryPrintDataInfoBO = deliveryPrintInfoBO.getData();
        logger.info("电子面单：订单号{}--快递单号{}", deliveryOrderParam.getOrderNumber(), deliveryPrintDataInfoBO.getKuaidinum());
        return deliveryPrintDataInfoBO.getKuaidinum();
    }

    private static void checkInfo(DeliveryOrderItemParam deliveryOrderParam, Quick100 quick100) {
        if (Objects.isNull(quick100) || StrUtil.isBlank(quick100.getKey()) || StrUtil.isBlank(quick100.getSecret())) {
            // 快递100配置为空或缺失
            throw new YamiShopBindException("yami.quick100.is.null");
        }
        if (!quick100.getIsPrint()) {
            // 平台未开启电子面单功能
            throw new YamiShopBindException("yami.delivery.print.config.is.null");
        }
        if (Objects.isNull(deliveryOrderParam.getOutletConfigId())) {
            // 快递公司以及发货地址信息不能为空
            throw new YamiShopBindException("yami.delivery.info.is.null");
        }
        if (Objects.isNull(deliveryOrderParam.getPrinterId())) {
            // 打印机信息不能为空
            throw new YamiShopBindException("yami.print.is.null");
        }
    }

    private static Map<String, Object> getOrderReqMap(DeliveryOrderItemParam deliveryOrderDTO, OutletConfig outletConfig, Printer printer,
                                                      DeliveryCompanyType deliveryCompanyType, Map<String, Object> recManMap,
                                                      Map<String, Object> sendManMap, Quick100 quick100) {
        Map<String, Object> orderReqMap = new HashMap<>(Constant.INITIAL_CAPACITY);
        // 电子面单客户账户或月结账号
        orderReqMap.put("partnerId", outletConfig.getPartnerId());
        // 电子面单密码
        orderReqMap.put("partnerKey", outletConfig.getPartnerKey());
        // 电子面单密钥
        orderReqMap.put("net", outletConfig.getNet());
        // 电子面单承载编号
        orderReqMap.put("code", deliveryCompanyType.getCode());
        // 快递公司编码
        orderReqMap.put("kuaidicom", deliveryCompanyType.getKuaidicom());
        orderReqMap.put("recMan", recManMap);
        orderReqMap.put("sendMan", sendManMap);
        // 包裹总数量
        orderReqMap.put("count", 1);
        // 打印类型 默认云打印
        orderReqMap.put("printType", "CLOUD");
        StringBuilder sb = new StringBuilder(Constant.INITIAL_CAPACITY);
        if (CollUtil.isNotEmpty(deliveryOrderDTO.getSelectOrderItems())) {
            for (OrderItem selectOrderItem : deliveryOrderDTO.getSelectOrderItems()) {
                sb.append(selectOrderItem.getProdName()).append(StrUtil.COMMA);
            }
        }
        sb.deleteCharAt(sb.length() - 1);
        String spuName = sb.toString();
        if (spuName.length() >= MAX_CARGO_LENGTH) {
            spuName = spuName.substring(0, 16) + "...";
        }
        // 物品名称
        orderReqMap.put("cargo", spuName);
        // 快递100模板id
        orderReqMap.put("tempId", DeliveryCompanyType.getTempId(outletConfig.getDeliveryCompanyType(), outletConfig.getPaperSize()));
        // 打印设备
        orderReqMap.put("siid", printer.getSiid());
        // 沙箱模式，不会提交到快递公司
        if (quick100.getMock()) {
            orderReqMap.put("mock", "kd100@Mock");
        }
        return orderReqMap;
    }

    private Map<String, Object> getManInfoMap(String name, String mobile, Long userAddrId, String printAddr) {
        Map<String, Object> manInfoMap = new HashMap<>(MAP_INIT);
        // 姓名
        manInfoMap.put("name", name);
        // 手机号
        manInfoMap.put("mobile", mobile);
        // 所在完整地址
        if (Objects.nonNull(userAddrId)) {
            UserAddrOrder orderAddr = userAddrOrderService.getById(userAddrId);
            printAddr = orderAddr.getProvince() + orderAddr.getCity() + orderAddr.getArea() + orderAddr.getAddr();
        }
        manInfoMap.put("printAddr", printAddr);
        return manInfoMap;
    }
}
